﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestChemicalEquilibrium
{

     /*
     分析神经递质系统中各种反应
     T:神经递质, R:受体, M:第二信使, 
     Pc:合成酶, Pr:分解酶, PK:蛋白激酶, PP:蛋白磷酸酶
     G:G蛋白, +s:激活, +i:抑制
     [1]递质的合成
         T_ + (PcT_) -> T + (PcT_)
     [2]递质的分解
         T + (PrT) -> T_ + (PrT)
     [3]递质与受体结合
         T + R -> TR
     [4]递质与受体分离
         TR -> T + R
         
     [5]G蛋白的激活
         (TR) + G1G2 -> (TR) + G1 + G2
     [6]G蛋白与离子通道结合
         G2 + C -> G2C
     [7]G蛋白与离子通道分离
         G2C -> G2 + C
     [8]G蛋白与酶结合
         G1 + Ps -> G1Ps
     [9]G蛋白与酶分离
         G1Ps -> G1 + Ps
     [10]G蛋白失活
         G1 -> G1_
         G1_+ G2 -> G1G2
         
     [11]第二信使的激活
         (G1sPs) + M_ -> (G1sPs) + M
         (Ps) + M_ -> (Ps) + M
     [12]第二信使的失活
         [1]cAMP磷酸二脂酶(PDE)将cAMP破坏
         [2]Gi1与腺苷酸环化酶(AC)结合使AC失活,同是Gi2与Gs1结合,使Gs1失活
         (G1iPs) + M -> (G1iPs) + M_;
         (Ps) + M -> (Ps) + M_;
         
     [13]第二信使与离子通道结合
         M + C -> MC
     [14]第二信使与离子通道分离
         MC -> M + C
      
     [15]第二信使与蛋白激酶结合
         M + PK -> MPK
     [16]第二信使与蛋白激酶分离
         MPK -> M + PK
         
     [17]蛋白激酶激活离子通道
         (MPK) + C_ -> (MPK) + C
     [18]蛋白磷酸酶灭活离子通道
         (PP) + C -> (PP) + C_
         
     反应类型
         合成: A + B -> AB
         分解: AB -> A + B
         自失活: A -> A_
         催化激活: A_ + (P) -> A + (P)
         催化失活: A + (P) -> A_ + (P)
         催化分解: AB + (P) -> A + B + (P)
     */

    /// <summary>
    /// 化合分解平衡反应
    /// </summary>
    public class ReactCombineResolve
    {
        public Queue<Reactant> As, Bs, ABs, AB_s, C_s;
        public int PositiveVelocity , ReverseVelocity; //正, 逆反应速度
        int PositiveParameter, ReverseParameter;
        int PositiveEfficiency, ReverseEfficiency;

        public int GetACount() { return this.As.Count; }
        public int GetBCount() { return this.Bs.Count; }
        public int GetABCount() { return this.ABs.Count; }
        public int GetAB_Count() { return this.AB_s.Count; }
        public int GetC_Count() { return this.C_s.Count; }
        public int GetPositiveVelocity() { return this.PositiveVelocity; }
        public int GetReverseVelocity() { return this.ReverseVelocity; }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="As">反应物A</param>
        /// <param name="Bs">反应物B</param>
        /// <param name="ABs">化合的AB</param>
        /// <param name="AB_s">分解的AB</param>
        /// <param name="C_s">分解催化剂</param>
        /// <param name="activateParameter">化合速度参数 : [2, 100]</param>
        /// <param name="inactivateParameter">分解速度参数 : [2, 100]</param>
        public ReactCombineResolve(Queue<Reactant> As, Queue<Reactant> Bs, Queue<Reactant> ABs, Queue<Reactant> AB_s, Queue<Reactant> C_s, int positiveParameter, int reverseParameter, int positiveEfficiency, int reverseEfficiency)
        {
            this.As = As;
            this.Bs = Bs;
            this.ABs = ABs;
            this.AB_s = AB_s;
            this.C_s = C_s;
            this.PositiveParameter = positiveParameter;
            this.ReverseParameter = reverseParameter;
            this.PositiveEfficiency = positiveEfficiency;
            this.ReverseEfficiency = reverseEfficiency;

            if (As == null || Bs == null || ABs == null || AB_s == null) throw new Exception("React Error : Reactant is null!");

        }

        //化合
        public void Combine()
        {
            if (As.Count * Bs.Count == 0)
                this.PositiveVelocity = 0;
            else if (As.Count * Bs.Count / (As.Count + Bs.Count) < this.PositiveParameter)
                this.PositiveVelocity = 1;
            else
                this.PositiveVelocity = As.Count * Bs.Count / (As.Count + Bs.Count) / this.PositiveParameter;

            for (int i = 0; i < this.PositiveVelocity; i++)
            {
                if (this.As.Count == 0 || this.Bs.Count == 0
                    || this.AB_s.Count == 0) break;

                Reactant ab = this.AB_s.Dequeue();
                Reactant a = this.As.Dequeue();
                Reactant b = this.Bs.Dequeue();

                if (a != null && b != null && ab != null)
                {
                    ab.Combine(a);
                    ab.Combine(b);
                    this.ABs.Enqueue(ab);
                }
            }
        }

        //分解
        public void Resolve()
        {
            if (this.C_s != null)
            {
                if (this.ABs.Count * this.C_s.Count == 0)
                    this.ReverseVelocity = 0;
                else if (this.ABs.Count * this.C_s.Count * this.ReverseEfficiency / (this.ABs.Count + this.C_s.Count * this.ReverseEfficiency) < this.ReverseParameter)
                    this.ReverseVelocity = 1;
                else
                    this.ReverseVelocity = this.ABs.Count * this.C_s.Count * this.ReverseEfficiency / (this.ABs.Count + this.C_s.Count * this.ReverseEfficiency) / this.ReverseParameter;
            }
            else
                this.ReverseVelocity = (this.ABs.Count + this.ReverseParameter - 1) / this.ReverseParameter;

            for (int i = 0; i < this.ReverseVelocity; i++)
            {
                if (this.ABs.Count == 0) break;

                Reactant ab = this.ABs.Dequeue();
                Reactant a = ab.Resolve();
                Reactant b = ab.Resolve();

                if (a != null && b != null && ab != null)
                {
                    this.As.Enqueue(a);
                    this.Bs.Enqueue(b);
                    this.AB_s.Enqueue(ab);
                }
                else
                    this.ABs.Enqueue(ab);

            }

        }



    }

    /// <summary>
    /// 激活失活平衡反应
    /// </summary>
    public class ReactActivate
    {
        public Queue<Reactant> As, A_s, Cs, C_s;
        public int ActivateVelocity, InactivateVelocity;
        int ActivateParameter, InactivateParameter;
        int ActivateEfficiency, InactivateEfficiency;

        public int GetACount() { return this.As.Count; }
        public int GetA_Count() { return this.A_s.Count; }
        public int GetCCount() { return this.Cs.Count; }
        public int GetC_Count() { return this.C_s.Count; }
        public int GetActivateVelocity() { return this.ActivateVelocity; }
        public int GetInactivateVelocity() { return this.InactivateVelocity; }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="As">激活的A</param>
        /// <param name="A_s">失活的A</param>
        /// <param name="Cs">失活剂</param>
        /// <param name="C_s">激活剂</param>
        /// <param name="activateParameter">激活速度参数 : [2, 100]</param>
        /// <param name="inactivateParameter">失活速度参数 : [2, 100]</param>
        public ReactActivate(Queue<Reactant> As, Queue<Reactant> A_s, Queue<Reactant> Cs, Queue<Reactant> C_s, int activateParameter, int inactivateParameter, int activateEfficiency, int inactivateEfficiency)
        {
            this.As = As;
            this.A_s = A_s;
            this.Cs = Cs;
            this.C_s = C_s;
            this.ActivateParameter = activateParameter;
            this.InactivateParameter = inactivateParameter;
            this.ActivateEfficiency = activateEfficiency;
            this.InactivateEfficiency = inactivateEfficiency;

            if (As == null || A_s == null) throw new Exception("React Error : Reactant is null!");
        }

        /// <summary>
        /// 激活反应
        ///     A_ + (C_) -> A + (C_)
        /// </summary>
        public void Activate()
        {
            if (this.C_s != null)
            {
                if (this.A_s.Count * this.C_s.Count == 0)
                    this.InactivateVelocity = 0;
                else if (this.A_s.Count * this.C_s.Count * this.ActivateEfficiency / (this.A_s.Count + this.C_s.Count * this.ActivateEfficiency) < this.ActivateParameter)
                    this.InactivateVelocity = 1;
                else
                    this.InactivateVelocity = this.A_s.Count * this.C_s.Count * this.ActivateEfficiency / (this.A_s.Count + this.C_s.Count * this.ActivateEfficiency) / this.ActivateParameter;
            }
            else
                this.InactivateVelocity = (this.A_s.Count + this.ActivateParameter - 1) / this.ActivateParameter;

            for (int i = 0; i < this.InactivateVelocity; i++)
            {
                if (this.A_s.Count == 0) break;

                this.As.Enqueue(this.A_s.Dequeue());
            }
        }

        /// <summary>
        /// 灭活反应
        ///     A + (C_) -> A_ + (C_)
        /// </summary>
        public void Inactivate()
        {
            if (this.Cs != null)
            {
                if (this.As.Count * this.Cs.Count == 0)
                    this.ActivateVelocity = 0;
                else if (this.As.Count * this.Cs.Count * this.InactivateEfficiency / (this.As.Count + this.Cs.Count * this.InactivateEfficiency) < this.InactivateParameter)
                    this.ActivateVelocity = 1;
                else
                    this.ActivateVelocity = this.As.Count * this.Cs.Count * this.InactivateEfficiency / (this.As.Count + this.Cs.Count * this.InactivateEfficiency) / this.InactivateParameter;
            }
            else
                this.ActivateVelocity = (this.As.Count + this.InactivateParameter - 1) / this.InactivateParameter;

            for (int i = 0; i < this.ActivateVelocity; i++)
            {
                if (this.As.Count == 0) break;

                this.A_s.Enqueue(this.As.Dequeue());
            }
        }
    }

    public delegate int GetVoltageCallback();

    public class IonicEquilibrium
    {
        Queue<Reactant> Channel, IonIn, IonOut;
        float Conductance;
        int Potential;
        GetVoltageCallback GetVoltage;
        int Count;
        public int GetChannel() { return this.Channel.Count; }
        public int GetIonIn() { return this.IonIn.Count; }
        public int GetIonOut() { return this.IonOut.Count; }
        public int GetCount() { return this.Count; }

        /// <summary>
        /// 离子平衡
        /// </summary>
        /// <param name="channel">离子通道</param>
        /// <param name="ionIn">膜内离子</param>
        /// <param name="ionOut">膜外离子</param>
        /// <param name="conductance">膜电导</param>
        /// <param name="potential">平衡电位</param>
        /// <param name="getVoltage">获取膜电位</param>
        public IonicEquilibrium(Queue<Reactant> channel, Queue<Reactant> ionIn, Queue<Reactant> ionOut, float conductance, int potential, GetVoltageCallback getVoltage)
        {
            this.Channel = channel;
            this.IonIn = ionIn;
            this.IonOut = ionOut;
            this.Conductance = conductance;
            this.Potential = potential;
            this.GetVoltage = getVoltage;
        }

        /// <summary>
        /// 运输离子
        /// </summary>
        public void Transport()
        {
            int voltage = this.GetVoltage();

            this.Count = (int)((voltage - this.Potential) * this.Conductance * this.Channel.Count);

            if (Count > 0 && this.IonIn.Count > 0)
                for (int i = 0; i < Count; i++)
                {
                    if (this.IonIn.Count == 0) break;

                    this.IonOut.Enqueue(this.IonIn.Dequeue());
                }
            else if (Count < 0 && this.IonOut.Count > 0)
                for (int i = 0; i < -Count; i++)
                {
                    if (this.IonOut.Count == 0) break;

                    this.IonIn.Enqueue(this.IonOut.Dequeue());
                }
        }
    }

    public class IonicPump
    {
        Queue<Reactant> Pumps;
        Queue<Reactant>[] IonsIn,  IonsOut;
        int[] Counts, Thresholds;

        public IonicPump(Queue<Reactant> pumps, Queue<Reactant>[] ionsIn, Queue<Reactant>[] ionsOut, int[] counts, int[] thresholds)
        {
            this.Pumps = pumps;
            this.IonsIn = ionsIn;
            this.IonsOut = ionsOut;
            this.Counts = counts;
            this.Thresholds = thresholds;
        }

        public void Transport()
        {
            int length = this.IonsIn.Length;

            bool transport = true;

            for (int i = 0; i < length; i++)
            {
                Queue<Reactant> ionsIn = this.IonsIn[i];
                int count = this.Counts[i];
                int threshold = this.Thresholds[i];

                if (count > 0)
                {
                    transport = transport && ionsIn.Count < threshold;
                }
                else if (count < 0)
                {
                    transport = transport && ionsIn.Count > threshold;
                }

                if (!transport) break;
            }

            if (transport)
            {
                for (int i = 0; i < length; i++)
                {
                    Queue<Reactant> ionsIn = this.IonsIn[i];
                    Queue<Reactant> ionsOut = this.IonsOut[i];
                    int count = this.Counts[i] * this.Pumps.Count;

                    if (count > 0)
                    {
                        for (int j = 0; j < count; j++)
                        {
                            ionsIn.Enqueue(ionsOut.Dequeue());
                        }
                    }
                    else if (count < 0)
                    {
                        for (int j = 0; j < -count; j++)
                        {
                            ionsOut.Enqueue(ionsIn.Dequeue());
                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// 反应物
    /// </summary>
    public class Reactant
    {
        public bool Activated = false;
        public bool Combined { get { return this.Reactants.Count > 0; } }

        protected Queue<Reactant> Reactants = new Queue<Reactant>();

        public Reactant(params Reactant[] reactants)
        {
            this.Combine(reactants);
        }

        //化合
        public void Combine(params Reactant[] reactants)
        {
            foreach (Reactant R in reactants)
            {
                this.Reactants.Enqueue(R);
            }
        }

        //分解
        public Reactant Resolve()
        {
            if (this.Reactants.Count > 0)
                return Reactants.Dequeue();
            else
                return null;
        }

    }


}
